package auth

import (
	"context"
	"crypto/md5"
	"fmt"
	"goProject/cfg"
	"goProject/db"
	"net/http"
	"strings"
	"time"

	"gitee.com/ruige_fun/util/std"

	"github.com/kataras/iris/v12"
)

// LoginAuthenticationByRoot 已登录校验，Root用户校验；
func LoginAuthenticationByRoot(c iris.Context) {
	if loginAuthentication(c) {
		roleID, _ := c.Values().GetInt(fmt.Sprint(c.GetID()))
		if roleID == 1 {
			c.Next()
			return
		}
		c.JSON(std.NewResp(http.StatusBadRequest, "您无权访问该请求，需要 ROOT 权限。", nil, nil))
	}
}

// LoginAuthenticationByAdmin 已登录校验，Admin用户校验；Root用户皆可通过。
func LoginAuthenticationByAdmin(c iris.Context) {
	if loginAuthentication(c) {
		roleID, _ := c.Values().GetInt(fmt.Sprint(c.GetID()))
		if roleID == 1 || roleID == 2 {
			c.Next()
			return
		}
		c.JSON(std.NewResp(http.StatusBadRequest, "您无权访问该请求，需要 Admin 权限。", nil, nil))
	}
}

// LoginAuthenticationByCASBIN 已登录校验，普通 User用户校验；Root、Admin用户皆可通过。
func LoginAuthenticationByCASBIN(c iris.Context) {
	if loginAuthentication(c) {
		roleID, _ := c.Values().GetInt(fmt.Sprint(c.GetID()))
		if roleID == 1 || roleID == 2 {
			c.Next()
			return
		}
		//请求鉴权
		bl, _ := CASBIN.Enforce(fmt.Sprint(roleID), c.Path(), c.Method())
		if bl {
			c.Next()
			return
		}
		c.JSON(std.NewResp(http.StatusBadRequest, "无权限或请稍后再试", nil, nil))
	}
}

// LoginAuthenticationByMy 已登录校验，任何已登录的用户，都校验通过。
func LoginAuthenticationByMy(c iris.Context) {
	if loginAuthentication(c) {
		c.Next()
	}
}

// loginAuthentication 已登录校验
func loginAuthentication(c iris.Context) bool {
	myIP := c.RemoteAddr()
	myToken := c.GetHeader("Authorization")
	if strings.HasPrefix(myToken, "Bearer ") {
		myToken = myToken[7:]
	}
	if v := db.RedisToken.Get(context.Background(), fmt.Sprint(cfg.Config.Main.ProjectName+"_sign_blacklist_", c.RemoteAddr())).Val(); v != "" {
		c.JSON(std.NewResp(http.StatusBadRequest, "您的 IP 最近存在异常操作，已封停 10 分钟，请 10 分钟后再试。", nil, nil))
		return false
	}
	mySign := c.GetHeader("Sign")
	if mySign != fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprint(myToken, "__/admin", c.Request().URL.Path)))) &&
		mySign != fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprint(myToken, "__", c.Request().URL.Path)))) {
		//请求签名错误，一看就知道有人想干坏事。
		db.RedisToken.Set(context.Background(), fmt.Sprint(cfg.Config.Main.ProjectName+"_sign_blacklist_", c.RemoteAddr()), time.Now().Unix()+600, time.Minute*10)
		c.JSON(std.NewResp(http.StatusInternalServerError, "请求签名错误，您的 IP 将被封停 10 分钟。", nil, nil))
		return false
	}
	it, err := ParseToken(myToken, myIP)
	if err != nil {
		c.JSON(std.NewResp(http.StatusUnauthorized, "登录身份验证失败，请重新登录", "", ""))
		return false
	}
	if str, _ := Token.Get(fmt.Sprint(it.ID)); str != myToken {
		c.JSON(std.NewResp(http.StatusUnauthorized, "您的登录已失效，请重新登录", "", ""))
		return false
	}
	c.SetID(it.ID) //设置用户ID
	roleID, _ := Role.Get(fmt.Sprint(it.ID))
	if roleID <= 0 {
		roleID = 100
	}
	c.Values().Set(fmt.Sprint(it.ID), roleID)
	return true
}
